﻿using Microsoft.EntityFrameworkCore;
using MinimalistFoodStreet.BackEnd.Infrastructure.Attributes;
using MinimalistFoodStreet.BackEnd.Infrastructure.Dtos.Response;
using MinimalistFoodStreet.BackEnd.Server.IServer;
using MinimalistFoodStreet.BackEnd.Server.Server.Tables;

namespace MinimalistFoodStreet.BackEnd.Server.Server
{
    [InjectClass]
    public class StatisticsServer : IStatisticsServer
    {
        private readonly ServerRepository _serverRepository;
        public StatisticsServer(DbContext dbContext)
        {
            _serverRepository = new ServerRepository(dbContext);
        }

        public async Task<ResponseApiDto> GetAdminHomeStatistics(string timeType)
        {
            DateTime curBeginTime;
            DateTime curEndTime;
            DateTime prevBeginTime;
            DateTime prevEndTime;
            DateTime now = DateTime.Now;
            DateTime nowZero = new DateTime(now.Year, now.Month, now.Day);
            switch (timeType)
            {
                case "date":
                    curBeginTime = nowZero;
                    curEndTime = now;
                    prevBeginTime = curBeginTime.AddDays(-1);
                    prevEndTime = curEndTime.AddDays(-1);
                    break;
                case "week":
                    curBeginTime = nowZero.AddDays(-(((int)now.DayOfWeek) > 0 ? ((int)now.DayOfWeek) - 1 : 6));
                    curEndTime = now;
                    prevBeginTime = curBeginTime.AddDays(-7);
                    prevEndTime = curEndTime.AddDays(-7);
                    break;
                case "month":
                    curBeginTime = new DateTime(now.Year, now.Month, 1);
                    curEndTime = now;
                    prevBeginTime = curBeginTime.AddMonths(-1);
                    prevEndTime = curEndTime.AddMonths(-1);
                    break;
                case "year":
                    curBeginTime = new DateTime(now.Year, 1, 1);
                    curEndTime = now;
                    prevBeginTime = curBeginTime.AddYears(-1);
                    prevEndTime = curEndTime.AddYears(-1);
                    break;
                default: return ResponseApiDto.Fail("请提供正确的时间类别（date,week,month,year）");
            }
            // 计算当前时段的数据
            var curCompleteIq = _serverRepository.ordersEFCore.Query(d => d.OCompleteTime != null && curBeginTime <= d.OCompleteTime && d.OCompleteTime < curEndTime);
            var curAllIq = _serverRepository.ordersEFCore.Query(d => curBeginTime <= d.OCreateTime && d.OCreateTime < curEndTime);
            var curNewUserCount = await _serverRepository.accountsEFCore.Query(d => d.AEndpoint == "business" && curBeginTime <= d.ACreateTime && d.ACreateTime < curEndTime).CountAsync();
            var curConversionUserCount = await _serverRepository.accountsEFCore.Query(d => d.AEndpoint == "business" && curBeginTime <= d.ACreateTime && d.ACreateTime < curEndTime && d.Businessses.First().Orders.Where(d => d.OCompleteTime != null).Any()).CountAsync();
            ResponseGetAdminHomeStatisticsDto data = new ResponseGetAdminHomeStatisticsDto
            {
                sumSales = await curCompleteIq.SumAsync(d => (decimal)d.OPayMoney),
                sumOrderCount = await curAllIq.CountAsync(),
                newUserCount = curNewUserCount,
                conversionRate = curNewUserCount != 0 ? ((float)curConversionUserCount / curNewUserCount) : 0
            };
            switch (timeType)
            {
                case "date":
                    data.chart1Data = await curCompleteIq.GroupBy(d => d.OCompleteTime.Value.Hour).Select(d => new Chart1 { time = d.Key.ToString() + "时", sales = (decimal)d.Sum(e => e.OPayMoney) }).ToListAsync();
                    break;
                case "week":
                    data.chart1Data = await curCompleteIq.GroupBy(d => d.OCompleteTime.Value.DayOfWeek).Select(d => new Chart1 { time = d.Key==DayOfWeek.Monday?"周一":d.Key==DayOfWeek.Tuesday?"周二":d.Key==DayOfWeek.Wednesday?"周三":d.Key==DayOfWeek.Thursday?"周四":d.Key==DayOfWeek.Friday?"周五":d.Key==DayOfWeek.Saturday?"周六":d.Key==DayOfWeek.Sunday?"周日":"未知", sales = (decimal)d.Sum(e => e.OPayMoney) }).ToListAsync();
                    break;
                case "month":
                    data.chart1Data = await curCompleteIq.GroupBy(d => d.OCompleteTime.Value.Day).Select(d => new Chart1 { time = d.Key.ToString() + "号", sales = (decimal)d.Sum(e => e.OPayMoney) }).ToListAsync();
                    break;
                case "year":
                    data.chart1Data = await curCompleteIq.GroupBy(d => d.OCompleteTime.Value.Month).Select(d => new Chart1 { time = d.Key.ToString() + "月", sales = (decimal)d.Sum(e => e.OPayMoney) }).ToListAsync();
                    break;
            }
            List<int> oids = await curCompleteIq.Select(d => d.OId).ToListAsync();
            var odIq = _serverRepository.orderDetailsEFCore.Query(d => oids.Contains(d.OdOrderId));
            data.chart2Data = await odIq.GroupBy(d => new { tid = d.OdGoodTypeId, tname = d.OdGoodType.DValue }).Take(5).Select(d => new Chart2 { category = d.Key.tname, sales = (decimal)d.Sum(d => d.OdReceivedMoney) }).ToListAsync();
            data.chart3Data = await curAllIq.GroupBy(d => d.OStatus).Select(d => new Chart3 { name = d.Key == 0 ? "未接单" : d.Key == 1 ? "未发货" : d.Key == 2 ? "待接收" : d.Key == 3 ? "全部完成" : d.Key == 4 ? "部分完成" : d.Key == -1 ? "拒绝接单" : d.Key == -2 ? "商家取消" : d.Key == -3 ? "供应商取消" : d.Key == -4 ? "已拒收" : "未知状态", value = d.Count() }).ToListAsync();
            data.chart4Data = new List<Chart3>()
            {
                new Chart3
                {
                    name="0-49",
                    value=await curCompleteIq.Where(d=>d.OPayMoney<50).CountAsync()
                },new Chart3
                {
                    name="50-99",
                    value=await curCompleteIq.Where(d=>50<=d.OPayMoney&&d.OPayMoney<100).CountAsync()
                },new Chart3
                {
                    name="100-499",
                    value=await curCompleteIq.Where(d=>100<=d.OPayMoney&&d.OPayMoney<500).CountAsync()
                },new Chart3
                {
                    name="500-999",
                    value=await curCompleteIq.Where(d=>500<=d.OPayMoney&&d.OPayMoney<1000).CountAsync()
                },new Chart3
                {
                    name="1000-9999",
                    value=await curCompleteIq.Where(d=>1000<=d.OPayMoney&&d.OPayMoney<10000).CountAsync()
                },new Chart3
                {
                    name=">10000",
                    value=await curCompleteIq.Where(d=>10000<d.OPayMoney).CountAsync()
                }
            };
            // 计算前一时段的数据
            var prevCompleteIq = _serverRepository.ordersEFCore.Query(d => d.OCompleteTime != null && d.OCompleteTime >= prevBeginTime && d.OCompleteTime < prevEndTime);
            var prevAllIq = _serverRepository.ordersEFCore.Query(d => prevBeginTime <= d.OCreateTime && d.OCreateTime < prevEndTime);
            var prevNewUserCount = await _serverRepository.accountsEFCore.Query(d => d.AEndpoint == "business" && d.ACreateTime >= prevBeginTime && d.ACreateTime < prevEndTime).CountAsync();
            var prevConversionUserCount = await _serverRepository.accountsEFCore.Query(d => d.AEndpoint == "business" && curBeginTime <= d.ACreateTime && d.ACreateTime < curEndTime && d.Businessses.First().Orders.Where(d => d.OCompleteTime != null).Any()).CountAsync();
            var sumSales = await prevCompleteIq.SumAsync(d => d.OPayMoney);
            var sumOrderCount = await prevAllIq.CountAsync();
            var newUserCount = prevNewUserCount;
            float? conversionRate = prevNewUserCount != 0 ? ((float)curConversionUserCount / prevNewUserCount) : 0;

            data.sumSalesMom = sumSales != 0 ? ((float)(data.sumSales / sumSales) - 1) : null;
            data.sumOrderCountMom = sumOrderCount != 0 ? ((float)data.sumOrderCount / sumOrderCount - 1) : null;
            data.newUserCountMon = newUserCount != 0 ? ((float)data.newUserCount / newUserCount - 1) : null;
            data.conversionRateMom = conversionRate != 0 ? (data.conversionRate / conversionRate) : null;

            return ResponseApiDto.Ok("数据已获取", data);
        }

        public async Task<ResponseApiDto> GetSupplierChartStatistics(string timeType, int supplierId)
        {
            DateTime curBeginTime;
            DateTime curEndTime;
            DateTime prevBeginTime;
            DateTime prevEndTime;
            DateTime now = DateTime.Now;
            DateTime nowZero = new DateTime(now.Year, now.Month, now.Day);
            switch (timeType)
            {
                case "date":
                    curBeginTime = nowZero;
                    curEndTime = now;
                    prevBeginTime = curBeginTime.AddDays(-1);
                    prevEndTime = curEndTime.AddDays(-1);
                    break;
                case "week":
                    curBeginTime = nowZero.AddDays(-(((int)now.DayOfWeek) > 0 ? ((int)now.DayOfWeek) - 1 : 6));
                    curEndTime = now;
                    prevBeginTime = curBeginTime.AddDays(-7);
                    prevEndTime = curEndTime.AddDays(-7);
                    break;
                case "month":
                    curBeginTime = new DateTime(now.Year, now.Month, 1);
                    curEndTime = now;
                    prevBeginTime = curBeginTime.AddMonths(-1);
                    prevEndTime = curEndTime.AddMonths(-1);
                    break;
                case "year":
                    curBeginTime = new DateTime(now.Year, 1, 1);
                    curEndTime = now;
                    prevBeginTime = curBeginTime.AddYears(-1);
                    prevEndTime = curEndTime.AddYears(-1);
                    break;
                default: return ResponseApiDto.Fail("请提供正确的时间类别（date,week,month,year）");
            }
            ResponseGetSupplierChartStatisticsDto data = new ResponseGetSupplierChartStatisticsDto();
            // 计算当前时段的数据
            var curCompleteIq = _serverRepository.ordersEFCore.Query(d => d.OCompleteTime != null && d.OSupplierId == supplierId && curBeginTime <= d.OCompleteTime && d.OCompleteTime < curEndTime);
            var curAllIq = _serverRepository.ordersEFCore.Query(d => d.OSupplierId == supplierId && curBeginTime <= d.OCreateTime && d.OCreateTime < curEndTime);
            switch (timeType)
            {
                case "date":
                    data.chart1Data = await curCompleteIq.GroupBy(d => d.OCompleteTime.Value.Hour).Select(d => new Chart1 { time = d.Key.ToString() + "时", sales = (decimal)d.Sum(e => e.OPayMoney) }).ToListAsync();
                    break;
                case "week":
                    data.chart1Data = await curCompleteIq.GroupBy(d => d.OCompleteTime.Value.Day).Select(d => new Chart1 { time = d.Key.ToString() + "号", sales = (decimal)d.Sum(e => e.OPayMoney) }).ToListAsync();
                    break;
                case "month":
                    data.chart1Data = await curCompleteIq.GroupBy(d => d.OCompleteTime.Value.Day).Select(d => new Chart1 { time = d.Key.ToString() + "号", sales = (decimal)d.Sum(e => e.OPayMoney) }).ToListAsync();
                    break;
                case "year":
                    data.chart1Data = await curCompleteIq.GroupBy(d => d.OCompleteTime.Value.Month).Select(d => new Chart1 { time = d.Key.ToString() + "月", sales = (decimal)d.Sum(e => e.OPayMoney) }).ToListAsync();
                    break;
            }
            List<int> oids = await curCompleteIq.Select(d => d.OId).ToListAsync();
            var odIq = _serverRepository.orderDetailsEFCore.Query(d => oids.Contains(d.OdOrderId));
            data.chart2Data = await odIq.GroupBy(d => new { tid = d.OdGoodTypeId, tname = d.OdGoodType.DValue }).Take(5).Select(d => new Chart2 { category = d.Key.tname, sales = (decimal)d.Sum(d => d.OdReceivedMoney) }).ToListAsync();
            data.chart3Data = await curAllIq.GroupBy(d => d.OStatus).Select(d => new Chart3 { name = d.Key == 0 ? "未接单" : d.Key == 1 ? "未发货" : d.Key == 2 ? "待接收" : d.Key == 3 ? "全部完成" : d.Key == 4 ? "部分完成" : d.Key == -1 ? "拒绝接单" : d.Key == -2 ? "商家取消" : d.Key == -3 ? "供应商取消" : d.Key == -4 ? "已拒收" : "未知状态", value = d.Count() }).ToListAsync();
            data.chart4Data = new List<Chart3>()
            {
                new Chart3
                {
                    name="0-49",
                    value=await curCompleteIq.Where(d=>d.OPayMoney<50).CountAsync()
                },new Chart3
                {
                    name="50-99",
                    value=await curCompleteIq.Where(d=>50<=d.OPayMoney&&d.OPayMoney<100).CountAsync()
                },new Chart3
                {
                    name="100-499",
                    value=await curCompleteIq.Where(d=>100<=d.OPayMoney&&d.OPayMoney<500).CountAsync()
                },new Chart3
                {
                    name="500-999",
                    value=await curCompleteIq.Where(d=>500<=d.OPayMoney&&d.OPayMoney<1000).CountAsync()
                },new Chart3
                {
                    name="1000-9999",
                    value=await curCompleteIq.Where(d=>1000<=d.OPayMoney&&d.OPayMoney<10000).CountAsync()
                },new Chart3
                {
                    name=">10000",
                    value=await curCompleteIq.Where(d=>10000<d.OPayMoney).CountAsync()
                }
            };
            return ResponseApiDto.Ok("数据已获取", data);
        }

        public async Task<ResponseApiDto> GetSupplierHomeStatistics(int supplierId)
        {
            ResponseGetSupplierHomeStatisticsDto data = new ResponseGetSupplierHomeStatisticsDto();
            DateTime now = DateTime.Now;
            DateTime nowZero = new DateTime(now.Year, now.Month, now.Day);
            data.todayOrderCount = await _serverRepository.ordersEFCore.Query(d => d.OSupplierId == supplierId && d.OCreateTime > nowZero).CountAsync();
            data.todayFinishedOrderCount = await _serverRepository.ordersEFCore.Query(d => d.OSupplierId == supplierId && d.OCreateTime > nowZero && d.OCompleteTime != null).CountAsync();
            data.awaitActionOrderCount = data.todayOrderCount - data.todayFinishedOrderCount;
            data.todaySumSales = await _serverRepository.ordersEFCore.Query(d => d.OSupplierId == supplierId && d.OCreateTime > nowZero && d.OCompleteTime != null).SumAsync(d => (decimal)d.OPayMoney);
            return ResponseApiDto.Ok("数据已获取", data);
        }
    }
}
